﻿using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConfigurationDemo
{
    public static class ConfigurationExtensions
    {
        //可以通过委托使调用方更加灵活的配置源
        public static IConfigurationBuilder Add<TSource>(this IConfigurationBuilder builder, Action<TSource>? configureSource) where TSource : IConfigurationSource, new()
        {
            var source = new TSource();
            configureSource?.Invoke(source);
            return builder.Add(source);
        }

        public static string? GetConnectionString(this IConfiguration configuration, string name)
        {
            return configuration?.GetSection("ConnectionStrings")[name];
        }

        public static IEnumerable<KeyValuePair<string, string?>> AsEnumerable(this IConfiguration configuration) => configuration.AsEnumerable(makePathsRelative: false);

  
        public static IEnumerable<KeyValuePair<string, string?>> AsEnumerable(this IConfiguration configuration, bool makePathsRelative)
        {
            var stack = new Stack<IConfiguration>();
            stack.Push(configuration);
            int prefixLength = (makePathsRelative && configuration is IConfigurationSection rootSection) ? rootSection.Path.Length + 1 : 0;
            while (stack.Count > 0)
            {
                IConfiguration config = stack.Pop();
                // Don't include the sections value if we are removing paths, since it will be an empty key
                if (config is IConfigurationSection section && (!makePathsRelative || config != configuration))
                {
                    yield return new KeyValuePair<string, string?>(section.Path.Substring(prefixLength), section.Value);
                }
                foreach (IConfigurationSection child in config.GetChildren())
                {
                    stack.Push(child);
                }
            }
        }

        public static bool Exists([NotNullWhen(true)] this IConfigurationSection? section)
        {
            if (section == null)
            {
                return false;
            }
            return section.Value != null || section.GetChildren().Any();
        }

        public static IConfigurationSection GetRequiredSection(this IConfiguration configuration, string key)
        {
            //.ThrowIfNull(configuration);

            IConfigurationSection section = configuration.GetSection(key);
            if (section.Exists())
            {
                return section;
            }

            throw new InvalidOperationException();
        }
    }
}
